/* Console example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <stdio.h>
#include <string.h>
#include "esp_system.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "esp_vfs_fat.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "PikaObj.h"
#include <time.h>
#include "pika_hal.h"
#include "lvgl.h"


//#define USING_LVGL 1

#define LVGL_TASK_STACK_SIZE 1024 * 32
#define LVGL_TASK_PRIORITY 5
static const char* TAG = "pika";

/*
#include "esp_netif.h"
#include "esp_netif_sntp.h"



void initialize_sntp(void)
{
    ESP_LOGI(TAG, "Initializing SNTP");
    esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
                               ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org" ) );
    esp_netif_sntp_init(&config);
}

static esp_err_t obtain_time(void)
{
    // wait for time to be set
    int retry = 0;
    const int retry_count = 10;
    while (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(2000)) != ESP_OK && ++retry < retry_count) {
        ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
    }
    if (retry == retry_count) {
        return ESP_FAIL;
    }
    return ESP_OK;
}
*/

#ifdef CONFIG_USING_FLASHDB
#include "flashdb.h"

/*
static uint32_t boot_count = 0;
static time_t boot_time[10] = {0, 1, 2, 3};
// default KV nodes 
static struct fdb_default_kv_node default_kv_table[] = {
    {"username", "armink", 0},                       // string KV 
    {"password", "123456", 0},                       // string KV 
    {"boot_count", &boot_count, sizeof(boot_count)}, // int type KV 
    {"boot_time", &boot_time, sizeof(boot_time)},    // int array type KV 
};
*/


/* KVDB object */
static struct fdb_kvdb kvdb = {0};
/* TSDB object */
struct fdb_tsdb tsdb = {0};
/* counts for simulated timestamp */
static int counts = 0;
static SemaphoreHandle_t s_lock = NULL;

extern void kvdb_basic_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_string_sample(fdb_kvdb_t kvdb);
extern void kvdb_type_blob_sample(fdb_kvdb_t kvdb);
extern void tsdb_sample(fdb_tsdb_t tsdb);

static void lock(fdb_db_t db)
{
    xSemaphoreTake(s_lock, portMAX_DELAY);
}

static void unlock(fdb_db_t db)
{
    xSemaphoreGive(s_lock);
}

static fdb_time_t get_time(void)
{
    /* Using the counts instead of timestamp.
     * Please change this function to return RTC time.
     */
    return ++counts;
}

int flashdb_demo(void)
{
    fdb_err_t result;
    uint32_t* boot_count = (uint32_t*) malloc(sizeof(uint32_t));
    time_t* boot_time = (time_t*) malloc(10* sizeof(time_t));
    *boot_count=0;
    boot_time[0]=0;
    boot_time[1]=1;

  struct fdb_default_kv_node* def_kv_table =(struct fdb_default_kv_node*) malloc(4 * sizeof(struct fdb_default_kv_node));
  def_kv_table[0].key = strdup("username");
  def_kv_table[0].value= strdup("armink");
  def_kv_table[0].value_len = 0;
  def_kv_table[1].key = strdup("password");
  def_kv_table[1].value= strdup("123456");
  def_kv_table[1].value_len = 0;
  def_kv_table[2].key = strdup("boot_count");
  def_kv_table[2].value= boot_count;
  def_kv_table[2].value_len = sizeof(*boot_count);
  def_kv_table[3].key = strdup("boot_time");
  def_kv_table[3].value= boot_time;
  def_kv_table[3].value_len = sizeof(*boot_time);

    if (s_lock == NULL)
    {
        s_lock = xSemaphoreCreateCounting(1, 1);
        assert(s_lock != NULL);
    }

    #ifdef CONFIG_FDB_USING_KVDB
    { /* KVDB Sample */
        struct fdb_default_kv default_kv;

        //default_kv.kvs = default_kv_table;
        //default_kv.num = sizeof(default_kv_table) / sizeof(default_kv_table[0]);

        default_kv.kvs = def_kv_table;
        default_kv.num = 4; //sizeof(def_kv_table) / sizeof(def_kv_table[0]);
        
        /* set the lock and unlock function if you want */
        fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_LOCK, lock);
        fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_UNLOCK, unlock);
        /* Key-Value database initialization
         *
         *       &kvdb: database object
         *       "env": database name
         * "fdb_kvdb1": The flash partition name base on FAL. Please make sure \
\
it's in FAL partition table.
         *              Please change to YOUR partition name.
         * &default_kv: The default KV nodes. It will auto add to KVDB when fir\
\
st initialize successfully.
         *        NULL: The user data if you need, now is empty.
         */
        result = fdb_kvdb_init(&kvdb, "env", "fdb_kvdb1", &default_kv, NULL);

        if (result != FDB_NO_ERR)
        {
            return -1;
        }
        /* run basic KV samples */
        kvdb_basic_sample(&kvdb);
        /* run string KV samples */
        kvdb_type_string_sample(&kvdb);
        /* run blob KV samples */
        kvdb_type_blob_sample(&kvdb);

        fdb_kv_print(&kvdb);
    }
#endif /* FDB_USING_KVDB */
    return 0;
#ifdef CONFIG_FDB_USING_TSDB
    { /* TSDB Sample */
        /* set the lock and unlock function if you want */
        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, lock);
        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, unlock);
        /* Time series database initialization
         *
         *       &tsdb: database object
         *       "log": database name
         * "fdb_tsdb1": The flash partition name base on FAL. Please make sure \
\
it's in FAL partition table.
         *              Please change to YOUR partition name.
         *    get_time: The get current timestamp function.
         *         128: maximum length of each log
         *        NULL: The user data if you need, now is empty.
         */
        result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, NULL);
        /* read last saved time for simulated timestamp */
        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &counts);

        if (result != FDB_NO_ERR)
        {
            return -1;
        }

        /* run TSDB sample */
        tsdb_sample(&tsdb);
    }
#endif /* FDB_USING_TSDB */

    return 0;
}

#endif

    
#ifdef CONFIG_USING_EPD
//KCF TEST
//void EPD_Init(void);
#endif

void io_init(char *name, int dir, int val) {
  pika_dev *pin = pika_hal_open(PIKA_HAL_GPIO, name);
  pika_hal_GPIO_config cfg = {0};
  cfg.dir = dir;
  pika_hal_ioctl(pin, PIKA_HAL_IOCTL_CONFIG, &cfg);
  pika_hal_ioctl(pin, PIKA_HAL_IOCTL_ENABLE);
  pika_hal_write(pin, &val, sizeof(val));
  pika_hal_close(pin);
}



#ifdef CONFIG_USING_SD_CARD
// test for PIKA_PI_WIRELESS:
#include "sd_fatfs.h"
#endif

#ifdef CONFIG_USING_LCD
#include "lcd_driver.h"
#endif

#ifdef CONFIG_USING_AHT20
#include "aht20_driver.h"
#endif

#ifdef CONFIG_USING_SHT3X
#include "sht3x_driver.h"
#endif


#ifdef CONFIG_USING_BEEP
#include "beep_driver.h"
#endif

#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
#include "driver/usb_serial_jtag.h"
#endif

#include "pikaScript.h"

/*
#ifdef CONFIG_ESP_CONSOLE_USB_CDC
#error This example is incompatible with USB CDC console. Please try "console_usb" example instead.
#endif // CONFIG_ESP_CONSOLE_USB_CDC

#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
#error This example is incompatible with USB serial JTAG console.
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
*/


#define PROMPT_STR CONFIG_IDF_TARGET

/* Console command history can be stored to and loaded from a file.
 * The easiest way to do this is to use FATFS filesystem on top of
 * wear_levelling library.
 */

#ifdef CONFIG_USING_SD_CARD
#define MOUNT_PATH "/data"
#else
#define MOUNT_PATH "/sd"
#endif

#define HISTORY_PATH MOUNT_PATH "/history.txt"

#ifdef CONFIG_USING_ERASE_TASK

void erase_task(void *pvParameter) {
  
  pika_dev *erase_key = pika_hal_open(PIKA_HAL_GPIO, CONFIG_ERASE_TASK_GPIO_IN);
  
  pika_hal_GPIO_config cfg = {0};
  cfg.dir = PIKA_HAL_GPIO_DIR_IN;
  cfg.pull = PIKA_HAL_GPIO_PULL_UP;

#if CONFIG_IDF_TARGET_ESP32
  pika_hal_ioctl(erase_key, PIKA_HAL_IOCTL_CONFIG, &cfg);
  pika_hal_ioctl(erase_key, PIKA_HAL_IOCTL_ENABLE);
#endif

// define the time to check erase after reset, 100 for 1 sec
#define CHECK_ERASE_AFTER_RESET 100
// define the time of erase key pressed just afer reset, 5 for 0.05 sec
#define MAX_AFTER_RESET 5

  int time_after_reset=0;

  int pressed = 0;
  int max = 500; // 5 seconds
  bool reset =false;
  uint32_t keyvalue=0;
  while (1) {
    time_after_reset ++;

    /* sleep 10 ms */
    vTaskDelay(10 / portTICK_PERIOD_MS);
    //uint32_t keyvalue = 0;
    pika_hal_read(erase_key, &keyvalue, sizeof(keyvalue));
    if (0 == keyvalue) {
      pressed++;
      
      // This part check erase key pressed within 1 s just after reset
      if (time_after_reset < CHECK_ERASE_AFTER_RESET) {
          if (pressed > MAX_AFTER_RESET) {
            reset= true;
            printf("[Info] erase key pressed within 1s after reset\n");
          }

      }

      // this part check erase key pressed for 5 s
      if (pressed > max) {
        reset =true;
      } else if ((pressed % 100)==0) {
        printf("[Info] erase key pressed(%d/%d)\n", pressed/100, max/100);
      }

    } else {
      pressed = 0;
    }
    
    if (reset) {
        printf("[Info] erase flash and reboot\n");
        remove(PIKA_SHELL_SAVE_APP_PATH);
        pika_platform_reboot();
    }

  }
}
#endif


static void initialize_filesystem(void)
{
    static wl_handle_t wl_handle;
    const esp_vfs_fat_mount_config_t mount_config = {
            .max_files = 4,
            .format_if_mount_failed = true
    };
    esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(MOUNT_PATH, "storage", &mount_config, &wl_handle);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
        return;
    }
}

static void initialize_nvs(void)
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK( nvs_flash_erase() );
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);
}

#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED

#else
static void initialize_console(void)
{
    /* Drain stdout before reconfiguring it */
    fflush(stdout);
    fsync(fileno(stdout));

    /* Disable buffering on stdin */
    setvbuf(stdin, NULL, _IONBF, 0);

    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
    esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
    /* Move the caret to the beginning of the next line on '\n' */
    esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);

    /* Configure UART. Note that REF_TICK is used so that the baud rate remains
     * correct while APB frequency is changing in light sleep mode.
     */
    const uart_config_t uart_config = {
            .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
            .data_bits = UART_DATA_8_BITS,
            .parity = UART_PARITY_DISABLE,
            .stop_bits = UART_STOP_BITS_1,
#if SOC_UART_SUPPORT_REF_TICK
        .source_clk = UART_SCLK_REF_TICK,
#elif SOC_UART_SUPPORT_XTAL_CLK
        .source_clk = UART_SCLK_XTAL,
#endif
    };
    /* Install UART driver for interrupt-driven reads and writes */
    ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
            256, 0, 0, NULL, 0) );
    ESP_ERROR_CHECK( uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config) );

    /* Tell VFS to use UART driver */
    esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);

    /* Initialize the console */
    esp_console_config_t console_config = {
            .max_cmdline_args = 8,
            .max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
            .hint_color = atoi(LOG_COLOR_CYAN)
#endif
    };
    ESP_ERROR_CHECK( esp_console_init(&console_config) );

    /* Configure linenoise line completion library */
    /* Enable multiline editing. If not set, long commands will scroll within
     * single line.
     */
    linenoiseSetMultiLine(1);

    /* Tell linenoise where to get command completions and hints */
    linenoiseSetCompletionCallback(&esp_console_get_completion);
    linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);

    /* Set command history size */
    linenoiseHistorySetMaxLen(100);

    /* Set command maximum length */
    linenoiseSetMaxLineLen(console_config.max_cmdline_length);

    /* Don't return empty lines */
    linenoiseAllowEmpty(false);

#if CONFIG_STORE_HISTORY
    /* Load command history from filesystem */
    linenoiseHistoryLoad(HISTORY_PATH);
#endif
}
#endif //CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED



void print_info(void)
{
    /* Print chip information */
    esp_chip_info_t chip_info;
    uint32_t flash_size;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
           CONFIG_IDF_TARGET,
           chip_info.cores,
           (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
           (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

    unsigned major_rev = chip_info.revision / 100;
    unsigned minor_rev = chip_info.revision % 100;
    printf("silicon revision v%d.%d, ", major_rev, minor_rev);
    if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
        printf("Get flash size failed");
        return;
    }

    printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
    printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());

}

#if CONFIG_USING_LVGL

#define MY_DISP_HOR_RES X_MAX_PIXEL
#define MY_DISP_VER_RES Y_MAX_PIXEL


void disp_flush(struct _lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p){
  uint16_t *buf = (uint16_t *) color_p;
  LCD_DrawRegin(area->x1, area->y1, area->x2 + 1, area->y2 + 1, buf);
  lv_disp_flush_ready(disp_drv);
}

void lv_tick_task(void *arg) {

  (void)arg;

  while (1) {
    lv_tick_inc(10); // 10 ms passed
    vTaskDelay(pdMS_TO_TICKS(10)); //Delay for 10ms
  }
}


void lvgl_task(void *pvParameter) {
  (void)pvParameter; // 防止未使用的参数警告

  while (1) {
    lv_task_handler();
    // printf("lvgl_task\r\n");
    vTaskDelay(pdMS_TO_TICKS(10)); // 这会延迟10ms
  }
}

#endif // CONFIG_USING_LVGL

void app_main(void)
{
    print_info();
    initialize_nvs();

    //initialize_sntp();
    //esp_err_t err = obtain_time();
    //printf("obtain_time err:%d", err);
    
#ifdef CONFIG_USING_FLASHDB
   printf("FlashDB ESP32 SPI Flash Demo\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is ESP32 chip with %d CPU cores, WiFi, ",
           chip_info.cores);

    printf("silicon revision %d, ", chip_info.revision);
    // rbg/kcf commented:
    //printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
     //      (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    flashdb_demo();
#endif

#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
    ESP_LOGI(TAG, "init usb_serial_jtag");        
    usb_serial_jtag_driver_config_t usb_serial_jtag_config = {
      .rx_buffer_size = 1024 * 8, .tx_buffer_size = 1024};
    usb_serial_jtag_driver_install(&usb_serial_jtag_config);
    esp_vfs_usb_serial_jtag_use_driver();
    ESP_LOGI(TAG, "init usb_serial_jtag done");    
#else
    initialize_console();
    ESP_LOGI(TAG, "init console done");        
#endif  //CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
  
#ifdef  CONFIG_USING_SD_CARD
  int retry = 0;
  printf("Initializing SD card...\r\n");
  while (0 != sd_fatfs_init()) {
    /*加入指示SD卡初始化失败代码*/
    vTaskDelay(1000);
    retry++;
    if (retry > 10) {
      printf("Failed to init SD card, rebooting...\r\n");
      pika_platform_reboot();
    }
  }
#else
    initialize_filesystem();    
#endif

#if CONFIG_USING_LCD
  printf("Initializing LCD...\r\n");
  LCD_Init();
  LCD_Fill(0, 0, Y_MAX_PIXEL, X_MAX_PIXEL, BLUE);
#endif

#if CONFIG_USING_LVGL
  lv_init();
    static lv_disp_draw_buf_t draw_buf_dsc_1;
    static lv_color_t buf_1[MY_DISP_HOR_RES * 10];                          /*A buffer for 10 rows*/
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);  /*Initialize the display buffer*/

     static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/

    /*Set up the functions to access to your display*/

    /*Set the resolution of the display*/
    disp_drv.hor_res = MY_DISP_HOR_RES;
    disp_drv.ver_res = MY_DISP_VER_RES;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;

    /*Set a display buffer*/
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /* Finally register the driver */
    lv_disp_drv_register(&disp_drv);

    // 创建LVGL时钟任务
    xTaskCreate(lv_tick_task, "lv_tick_task", 1024, NULL, 5, NULL);
    // 创建LVGL任务
    xTaskCreate(lvgl_task,            // 任务函数
              "LVGL Task",          // 任务名称
              LVGL_TASK_STACK_SIZE, // 堆栈大小
              NULL,                 // 传递给任务函数的参数
              LVGL_TASK_PRIORITY,   // 任务优先级
              NULL // 任务句柄（不需要可以设置为NULL）
		);
#endif

#if CONFIG_USING_EPD
  // KCF TEST
  //EPD_Init();
#endif
  

#if CONFIG_USING_AHT20
  printf("Initializing AHT20...\r\n");
  aht20_init();
  AHT20_Data data;
  aht20_read(&data);
  printf("Temperature: %f, Humidity: %f\r\n", data.temperature, data.humidity);
#endif

#if CONFIG_USING_SHT3X
  printf("Initializing SHT3X...\r\n");
  sht3x_init();
  SHT3X_Data data;
  if (sht3x_read(&data)==0) {
    printf("Temperature: %f, Humidity: %f\r\n", data.temperature, data.humidity);
  } else {
    printf("sht3x read error");
  }
#endif
  
#if CONFIG_USING_BEEP
  printf("Initializing beep...\r\n");
  beep_init();
  beep_on();
  vTaskDelay(100);
  beep_off();
  printf("Beep initialization completed!\r\n");
#endif
  

    /* Figure out if the terminal supports escape sequences */

#ifdef  CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED

#else
    int probe_status = linenoiseProbe();
    if (probe_status) { /* zero indicates success */
        printf("\n"
               "Your terminal application does not support escape sequences.\n"
               "Line editing and history features are disabled.\n"
               "On Windows, try using Putty instead.\n");
        linenoiseSetDumbMode(1);

    }
#endif

#ifdef CONFIG_USING_ERASE_TASK    
  // erase_task
  xTaskCreate(erase_task, "task_erase", 1024 * 4, NULL, 10,
              NULL); /* try to boot from sd card */

  vTaskDelay(1000 / portTICK_PERIOD_MS);
#endif

  PikaObj *root = NULL;
  FILE *fp = fopen(PIKA_SHELL_SAVE_APP_PATH, "rb");
  if (fp != NULL) {
    fclose(fp);
    printf("[Info] load app from sd card\n");
    root = newRootObj("pikaMain", New_PikaMain);
    obj_linkLibraryFile(root, PIKA_SHELL_SAVE_APP_PATH);
    obj_runModule(root, "main");
  } else {
    printf("[Info] load app from firmware\n");
    root = pikaPythonInit();
  }


    pikaPythonShell(root);
    
    while (1) {
        vTaskDelay(1000/ portTICK_PERIOD_MS);
    }
}

char pika_platform_getchar() {
#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
  while (1) {
    char buff[1] = {0};
    if (usb_serial_jtag_read_bytes(buff, 1, 100) > 0) {
      return buff[0];
    }
    vTaskDelay(1);
  }
#else
  return getchar();
#endif
}

int pika_platform_putchar(char ch) {
#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
  usb_serial_jtag_write_bytes(&ch, 1, 0);
#else
  fputc(ch, stdout);
#endif
  return 0;  
}



FILE *pika_platform_fopen(const char *filename, const char *modes) {
  return fopen(filename, modes);
}

int pika_platform_fclose(FILE *fp) { return fclose(fp); }

int pika_platform_fseek(FILE *fp, long offset, int whence) {
  return fseek(fp, offset, whence);
}

long pika_platform_ftell(FILE *fp) { return ftell(fp); }

size_t pika_platform_fread(void *ptr, size_t size, size_t count, FILE *fp) {
  return fread(ptr, size, count, fp);
}

size_t pika_platform_fwrite(const void *ptr, size_t size, size_t count,
                            FILE *fp) {
  return fwrite(ptr, size, count, fp);
}

void pika_platform_reboot(void)
{
  //esp_restart();
  abort();
}

